package com.zhentao.service.impl;

import com.alibaba.fastjson.JSON;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.zhentao.common.constants.ArticleConstants;
import com.zhentao.common.redis.CacheService;
import com.zhentao.mapper.ApArticleConfigMapper;
import com.zhentao.mapper.ApArticleContentMapper;
import com.zhentao.mapper.ArticleMapper;
import com.zhentao.model.article.dto.ArticleDto;
import com.zhentao.model.article.dto.ArticleHomeDto;
import com.zhentao.model.article.dto.ArticleInfoDto;
import com.zhentao.model.article.dto.LikesBehaviorDto;
import com.zhentao.model.article.pojo.ApArticle;
import com.zhentao.model.article.pojo.ApArticleConfig;
import com.zhentao.model.article.pojo.ApArticleContent;
import com.zhentao.model.article.vo.HotArticleVo;
import com.zhentao.model.common.dtos.ResponseResult;
import com.zhentao.model.common.enums.AppHttpCodeEnum;
import com.zhentao.model.mess.ArticleVisitStreamMess;
import com.zhentao.model.user.pojo.ApUser;
import com.zhentao.service.ArticleService;
import com.zhentao.utils.common.AppUserThreadLocalUtil;
import org.apache.commons.lang.StringUtils;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;

import java.util.*;
import java.util.stream.Collectors;

@Service
public class ArticleServiceImpl implements ArticleService {
    @Autowired
    private ArticleMapper articleMapper;

    @Autowired
    private CacheService cacheService;
    @Autowired
    private ApArticleContentMapper apArticleContentMapper;
    @Autowired
    private ApArticleConfigMapper apArticleConfigMapper;
    @Autowired
    private RedisTemplate<String,String > redisTemplate;
    private final static Integer MAX_PAGE_SIZE=50;
    @Override
    public ResponseResult load(Integer loadType, ArticleHomeDto articleHomeDto) {
        //校验参数 -size
        Integer size = articleHomeDto.getSize();
        if(size == null || size==0){ //如果为空 赋值为10
            size=10;
        }
        //如果size<50 size=size  如果size>50  size=50
        size=Math.min(size, MAX_PAGE_SIZE);
        articleHomeDto.setSize(size);

        //2.校验参数 -频道
        if (StringUtils.isBlank(articleHomeDto.getTag())){
            articleHomeDto.setTag("__all__");
        }
        //3.校验参数 -时间
        if(articleHomeDto.getMaxBehotTime()==null){
            articleHomeDto.setMaxBehotTime(new Date());
        }
        if(articleHomeDto.getMinBehotTime()==null){
            articleHomeDto.setMinBehotTime(new Date());
        }

        List<ApArticle> apArticles = articleMapper.loadArticleList(articleHomeDto, loadType);
        for (ApArticle apArticle : apArticles) {
            apArticle.setStId(apArticle.getId().toString());
        }
        return ResponseResult.okResult(apArticles);
    }

    @Override
    public ResponseResult saveArticle(ArticleDto dto) {
        if(dto == null){
//            校验参数
            return ResponseResult.errorResult(AppHttpCodeEnum.PARAM_INVALID);
        }
//        封装参数
        ApArticle apArticle=new ApArticle();
        BeanUtils.copyProperties(dto, apArticle);
//        进行保存 判断是增加还是修改
        if(dto.getId() == null){
//            增加
//            保存文章基本信息
            apArticle.setCreatedTime(new Date());
            apArticle.setPublishTime(new Date());
            articleMapper.insert(apArticle);
//            保存内容
            ApArticleContent content=new ApArticleContent();
            content.setArticleId(apArticle.getId());
            content.setContent(dto.getContent());
            apArticleContentMapper.insert(content);
//            保存配置表
            ApArticleConfig apArticleConfig=new ApArticleConfig();
            apArticleConfig.setArticleId(apArticle.getId());
            apArticleConfig.setIsComment(true);
            apArticleConfig.setIsDelete(false);
            apArticleConfig.setIsDown(false);
            apArticleConfig.setIsForward(true);
            apArticleConfigMapper.insert(apArticleConfig);
        }else { //修改文章
            articleMapper.updateById(apArticle);
//            修改内容
            QueryWrapper<ApArticleContent> wrapper=new QueryWrapper<>();
            wrapper.lambda().eq(ApArticleContent::getArticleId, dto.getId());
            ApArticleContent apArticleContent = apArticleContentMapper.selectOne(wrapper);
            apArticleContent.setContent(dto.getContent());
            apArticleContentMapper.updateById(apArticleContent);
        }


        return ResponseResult.okResult(apArticle.getId());
    }

    @Override
    public ResponseResult loadArticleBehavior(ArticleInfoDto dto) {
        ApUser user = AppUserThreadLocalUtil.getUser();
        if(user== null){
            return ResponseResult.errorResult(AppHttpCodeEnum.NEED_LOGIN);
        }
        if(dto == null){
            return ResponseResult.errorResult(AppHttpCodeEnum.PARAM_INVALID);
        }
        Map<String,Boolean> map=new HashMap<>();
        Object islike = redisTemplate.opsForHash().get("likes" + dto.getArticleId().toString(), user.getId().toString());
        Object isunlike = redisTemplate.opsForHash().get("unLikesBehavior"+dto.getArticleId().toString(),user.getId().toString());
        Object iscollection = redisTemplate.opsForHash().get("collectionNBehavior"+dto.getArticleId().toString(),user.getId().toString());
        Object isfollow = redisTemplate.opsForHash().get("userFollow"+dto.getArticleId().toString(),user.getId().toString());

        if(islike ==null){
            map.put("islike", false);
        }else{
            map.put("islike", true);
        }

        if(isunlike ==null){
            map.put("isunlike", false);
        }else{
            map.put("isunlike", true);
        }

        if(iscollection ==null){
            map.put("iscollection", false);
        }else{
            map.put("iscollection", true);
        }

        if(isfollow ==null){
            map.put("isfollow", false);
        }else{
            map.put("isfollow", true);
        }
        return ResponseResult.okResult(map);
    }

    @Override
    public ResponseResult load2(ArticleHomeDto dto, Integer type, boolean firstPage) {
        if(firstPage){
            String json=null;
            if(dto.getTag().equals("__all__")){
                json=redisTemplate.opsForValue().get(ArticleConstants.HOT_ARTICLE_FIRST_PAGE + ArticleConstants.DEFAULT_TAG);
            }
            if(StringUtils.isNotBlank(json)){
                List<HotArticleVo> hotArticleVos = JSON.parseArray(json, HotArticleVo.class);
                return ResponseResult.okResult(hotArticleVos);
            }
        }
        return load(type,dto);
    }

    @Override
    public void updateScore(ArticleVisitStreamMess mess) {
        //1.更新文章的阅读、点赞、收藏、评论的数量
        ApArticle apArticle = updateArticle(mess);
        //2.计算文章的分值
        Integer score = computeScore(apArticle);
        score = score * 3;
        //3.替换当前文章对应频道的热点数据
        replaceDataToRedis(apArticle, score, ArticleConstants.HOT_ARTICLE_FIRST_PAGE + apArticle.getChannelId());
        //4.替换推荐对应的热点数据
        replaceDataToRedis(apArticle, score, ArticleConstants.HOT_ARTICLE_FIRST_PAGE + ArticleConstants.DEFAULT_TAG);
    }

    /**
     * 替换数据并且存入到redis
     * @param apArticle
     * @param score
     * @param s
     */
    private void replaceDataToRedis(ApArticle apArticle, Integer score, String s) {
        String articleListStr = redisTemplate.opsForValue().get(s);
        if(StringUtils.isNotBlank(articleListStr)){
            List<HotArticleVo> hotArticleVos = JSON.parseArray(articleListStr, HotArticleVo.class);

            boolean flag=true;
            //如果缓存中存在该文章，只更新分值
            for (HotArticleVo hotArticleVo : hotArticleVos) {
                if(hotArticleVo.getId().equals(apArticle.getId())){
                    hotArticleVo.setScore(score);
                    flag=false;
                    break;
                }
            }
            //如果缓存中不存在，查询缓存中分值最小的一条数据，进行分值的比较，如果当前文章的分值大于缓存中的数据，就替换
            if(flag){
                if(hotArticleVos.size() >= 30){
                    List<HotArticleVo> collect = hotArticleVos.stream().sorted(Comparator.comparing(HotArticleVo::getScore)).collect(Collectors.toList());
                    HotArticleVo lasthotArticleVo = collect.get(collect.size() - 1);
                    if(lasthotArticleVo.getScore() < score){
                        collect.remove(lasthotArticleVo);
                        HotArticleVo hot=new HotArticleVo();
                        BeanUtils.copyProperties(apArticle, hot);
                        hot.setScore(score);
                        hotArticleVos.add(hot);
                    }
                }
            }else {
                HotArticleVo hot = new HotArticleVo();
                BeanUtils.copyProperties(apArticle, hot);
                hot.setScore(score);
                hotArticleVos.add(hot);
            }
            //缓存到redis
            hotArticleVos = hotArticleVos.stream().sorted(Comparator.comparing(HotArticleVo::getScore).reversed()).collect(Collectors.toList());
            redisTemplate.opsForValue().set(s,JSON.toJSONString(hotArticleVos));
        }
    }

    /**
     * 更新文章行为数量
     * @param mess
     */
    private ApArticle updateArticle(ArticleVisitStreamMess mess) {
        System.out.println(mess);
        ApArticle apArticle = articleMapper.selectById(mess.getArticleId());
        apArticle.setCollection(apArticle.getCollection()+mess.getCollect());
        apArticle.setLikes(apArticle.getLikes()+mess.getLike());
        apArticle.setViews(apArticle.getViews()+mess.getView());
        apArticle.setComment(apArticle.getComment()+mess.getComment());
        articleMapper.updateById(apArticle);
        return apArticle;
    }

    /**
     * 计算文章的具体分值
     * @param apArticle
     * @return
     */
    private Integer computeScore(ApArticle apArticle) {
        Integer score = 0;
        if(apArticle.getLikes() != null){
            score += apArticle.getLikes() * ArticleConstants.HOT_ARTICLE_LIKE_WEIGHT;
        }
        if(apArticle.getViews() != null){
            score += apArticle.getViews();
        }
        if(apArticle.getComment() != null){
            score += apArticle.getComment() * ArticleConstants.HOT_ARTICLE_COMMENT_WEIGHT;
        }
        if(apArticle.getCollection() != null){
            score += apArticle.getCollection() * ArticleConstants.HOT_ARTICLE_COLLECTION_WEIGHT;
        }
        return score;
    }
}
